package com.kernowsoft.wavefx;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Locale;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.IntentService;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Intent;
import android.util.Log;

public class ForecastUpdateService extends IntentService {

	// incoming requests:
	public static final String REQUEST_FX_UPDATE = "REQUEST_FX_UPDATE";
	public static final String REQUEST_SITELIST_UPDATE = "REQUEST_SITELIST_UPDATE";

	// incoming parameters:
	public static final String SITE_NAME = "SITE_NAME";

	// outgoing broadcasts:
	public static final String FX_UPDATED = "FX_UPDATED";
	public static final String SITELIST_UPDATED = "SITELIST_UPDATED";

	public static final String TAG = ForecastUpdateService.class
			.getSimpleName();

	public ForecastUpdateService() {
		super(TAG);
	}

	@Override
	protected void onHandleIntent(Intent intent) {

		String action = intent.getAction();
		Log.d(TAG, "ACTION is : [" + action + "]");
		if (action.contentEquals(REQUEST_FX_UPDATE)) {
			forecastUpdate(intent);
		} else if (action.contentEquals(REQUEST_SITELIST_UPDATE)) {
			sitelistUpdate(intent);
		} else {
			throw new UnsupportedOperationException(
					"Can't handle event action " + action);
		}
	}

	private void sitelistUpdate(Intent intent) {
		// build URL to download Fx data from:
		String strUrl = String.format(Locale.UK,
				"http://www.ncof.co.uk/~ncof_webuser/spectral_wave/sites.json");

//		Log.d(TAG, "Updating sites from: " + strUrl);
		URL url = null;
		try {
			url = new URL(strUrl);
		} catch (MalformedURLException e) {
			e.printStackTrace();
			return;
		}

		// download data from server:
		String json = downloadJSONData(url);
//		Log.d(TAG, "Got JSON String:\n" + json);

		// update database:
		updateSiteDbFromJSON(json);

		// broadcast that update is complete:
		Intent broadcastIntent = new Intent();
		broadcastIntent.setAction(SITELIST_UPDATED);
		broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT);
		sendBroadcast(broadcastIntent);
	}

	protected int updateSiteDbFromJSON(String strJson) {

		ContentValues[] cv;

		try {
			JSONArray aSites = new JSONArray(strJson);
			int len = aSites.length();
			Log.d(TAG, "Length of sitenames array" + len);
			cv = new ContentValues[len];
			for (int i = 0; i < len; i++) {
				cv[i] = new ContentValues();
				cv[i].put(WaveDataContentProvider.Locations.NAME,
						aSites.getString(i));
				cv[i].put(WaveDataContentProvider.Locations.LAT, 0.0); // TODO
				cv[i].put(WaveDataContentProvider.Locations.LON, 0.0); // TODO
			}
		} catch (JSONException e) {
			e.printStackTrace();
			return -1;
		}

		// get content resolver:
		ContentResolver cr = getApplication().getContentResolver();

		// delete existing entries:
		String where = null; // all rows
		cr.delete(WaveDataContentProvider.Locations.CONTENT_URI, where, null);

		// insert new entries:
		return cr.bulkInsert(WaveDataContentProvider.Locations.CONTENT_URI, cv);
	}

	private void forecastUpdate(Intent intent) {
		Log.d(TAG, "Forecast Update Service started");
		// decode intent:
		String sitename = intent.getStringExtra(SITE_NAME);
		if (sitename == null) {
			Log.e(TAG, "Error: forecast_update service: no sitename supplied.");
			return;
		}

		// build url to download fx data from:
		String strUrl = String
				.format(Locale.UK,
						"http://www.ncof.co.uk/~ncof_webuser/spectral_wave/%s_intparts.json",
						sitename);
		URL url = null;
		try {
			url = new URL(strUrl);
		} catch (MalformedURLException e) {
			e.printStackTrace();
			return;
		}

		// download data from server:
		String json = downloadJSONData(url);
//		Log.d(TAG, "Got JSON String:\n" + json);

		// update database
		updateFxDbFromJSON(sitename, json);

		// broadcast that update is complete:
		Intent broadcastIntent = new Intent();
		broadcastIntent.setAction(FX_UPDATED);
		broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT);
		broadcastIntent.putExtra(SITE_NAME, sitename);
		sendBroadcast(broadcastIntent);

	}

	public String downloadJSONData(URL url) {
		// download data from the server.
		String strJson = new String();

		try {
			URLConnection con = url.openConnection();

			BufferedReader in = new BufferedReader(new InputStreamReader(
					con.getInputStream()));

			int count;

			char[] buf = new char[256];

			while ((count = in.read(buf, 0, 255)) != -1) {
				strJson = strJson.concat(String.valueOf(buf, 0, count));
			}

			Log.i(TAG, "Done");
			in.close();

		} catch (MalformedURLException e) {
			Log.e(TAG, "Malformed URL: " + e.getMessage());
			e.printStackTrace();
		} catch (IOException e) {
			Log.e(TAG, "IO Exception: " + e.getMessage());
			e.printStackTrace();
		}

		return strJson;
	}

	protected int updateFxDbFromJSON(String strSite, String strJson) {

		ArrayList<ContentValues> aValues = new ArrayList<ContentValues>();
		Date vt = null;

		try {
			JSONObject json = new JSONObject(strJson);
			vt = new SimpleDateFormat("yyyy-MM-dd'T'H:mm:ss", Locale.getDefault()).parse(json
					.getString("validtime"));

			JSONArray aHsig = json.getJSONArray("hsig");
			JSONArray aTm = json.getJSONArray("tm");
			JSONArray aTp = json.getJSONArray("tp");
			JSONArray aTh = json.getJSONArray("th");
			JSONArray aWSpd = json.getJSONArray("wspd");
			JSONArray aWDir = json.getJSONArray("wdir");

			int fcstep = json.getInt("fcstep");
			int fchr = 0;
			int len = aHsig.length();
			for (int i = 0; i < len; i += 3) {

				JSONArray hsparts = aHsig.getJSONArray(i);
				JSONArray tmparts = aTm.getJSONArray(i);
				JSONArray tpparts = aTp.getJSONArray(i);
				JSONArray thparts = aTh.getJSONArray(i);

				ContentValues values = new ContentValues();

				values.put(WaveDataContentProvider.SiteForecast.SITENAME,
						strSite);

				// TODO: This needs to go in a separate table...
				values.put(WaveDataContentProvider.SiteForecast.VALID_DATETIME,
						new SimpleDateFormat("yyyyMMddHH", Locale.getDefault()).format(vt));

				values.put(
						WaveDataContentProvider.SiteForecast.FORECAST_PERIOD,
						fchr);

				values.put(WaveDataContentProvider.SiteForecast.WAVE_HSIG1,
						hsparts.getDouble(0));
				values.put(WaveDataContentProvider.SiteForecast.WAVE_TP1,
						tpparts.getDouble(0));
				values.put(WaveDataContentProvider.SiteForecast.WAVE_TM1,
						tmparts.getDouble(0));
				values.put(WaveDataContentProvider.SiteForecast.WAVE_MDIR1,
						thparts.getDouble(0));

				if (hsparts.length() > 1) {
					values.put(WaveDataContentProvider.SiteForecast.WAVE_HSIG2,
							hsparts.getDouble(1));
					values.put(WaveDataContentProvider.SiteForecast.WAVE_TP2,
							tpparts.getDouble(1));
					values.put(WaveDataContentProvider.SiteForecast.WAVE_TM2,
							tmparts.getDouble(1));
					values.put(WaveDataContentProvider.SiteForecast.WAVE_MDIR2,
							thparts.getDouble(1));
				}
				if (hsparts.length() > 2) {
					values.put(WaveDataContentProvider.SiteForecast.WAVE_HSIG3,
							hsparts.getDouble(2));
					values.put(WaveDataContentProvider.SiteForecast.WAVE_TP3,
							tpparts.getDouble(2));
					values.put(WaveDataContentProvider.SiteForecast.WAVE_TM3,
							tmparts.getDouble(2));
					values.put(WaveDataContentProvider.SiteForecast.WAVE_MDIR3,
							thparts.getDouble(2));
				}

				// wind:
				values.put(WaveDataContentProvider.SiteForecast.WIND_SPD, aWSpd.getDouble(i));
				values.put(WaveDataContentProvider.SiteForecast.WIND_DIR, aWDir.getDouble(i));

				// increment fc step
				fchr += 3 * fcstep;

				// add values to list:
				aValues.add(values);
			}
		} catch (JSONException e) {
			e.printStackTrace();
		} catch (java.text.ParseException e) {
			e.printStackTrace();
		}

		// returns the number of inserted rows:
		Log.d(TAG, "Chris: Updating rows in database");
		ContentValues[] vals = new ContentValues[aValues.size()];
		vals = aValues.toArray(vals);

		// delete old data for this site:
		getApplication().getContentResolver().delete(
				WaveDataContentProvider.SiteForecast.CONTENT_URI,
				WaveDataContentProvider.SiteForecast.SITENAME + " = '"
						+ strSite + "'", null);

		// update valid time;
		ContentValues cv = new ContentValues();
		cv.put(WaveDataContentProvider.SiteForecast.VALID_DATETIME,
				new SimpleDateFormat("yyyyMMddHH", Locale.getDefault()).format(vt));
		
		getApplication().getContentResolver().update(
				WaveDataContentProvider.SiteForecast.VALIDTIME_URI,
				cv,
				WaveDataContentProvider.SiteForecast.SITENAME + " = '"
						+ strSite + "'", null);

		// add new rows:
		return getApplication().getContentResolver().bulkInsert(
				WaveDataContentProvider.SiteForecast.CONTENT_URI, vals);

	}
}
